import ctypes, pathlib, threading, time
import os
from tracemalloc import Snapshot
from typing import Callable, Dict, List
import weakref

# 修正DLL路径，使用py_cpp_event目录下的DLL
dll_path = os.path.join(os.path.dirname(__file__), "..", "install", "event_bus.dll")

_SO = pathlib.Path(dll_path)
lib = ctypes.CDLL(str(_SO))

class CEvent(ctypes.Structure):
    _pack_ = 1
    _fields_ = [("id", ctypes.c_int),
                ("payload", ctypes.c_void_p),  # 使用c_void_p而不是c_char_p
                ("payload_size", ctypes.c_size_t)]

# 定义新的C函数
lib.eb_push.argtypes = [ctypes.POINTER(CEvent)]
lib.eb_pop.argtypes  = [ctypes.POINTER(CEvent)]
lib.eb_pop.restype   = ctypes.c_int

# 新增函数定义
lib.eb_create_event.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_size_t]
lib.eb_create_event.restype = ctypes.c_void_p

lib.eb_destroy_event.argtypes = [ctypes.c_void_p]
lib.eb_destroy_event.restype = None

# 新增：释放CEvent payload内存的函数
lib.eb_free_payload.argtypes = [ctypes.c_void_p]  # 使用c_void_p而不是c_char_p
lib.eb_free_payload.restype = None

lib.start.argtypes = None
lib.start.restype = None

class _GlobalPoller:
    _lock = threading.Lock()
    _instance = None
    _ref_count = 0
    _running = False
    _thread = None
    _busses = []

    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
            return cls._instance

    def add_bus(self, bus):
        """Add a bus to the poller."""
        import weakref
        with self._lock:
            self._busses.append(weakref.ref(bus, self._cleanup))
            self._ref_count += 1
            if not self._running or not self._thread.is_alive():
                self._running = True
                self._thread = threading.Thread(target=self._poll, daemon=True)
                self._thread.start()
    def remove_bus(self, bus):
        """Remove a bus from the poller."""
        with self._lock:
            self._busses = [wb for wb in self._busses if wb() is not bus]
            self._ref_count = max(self._ref_count - 1, 0)
            if self._ref_count == 0 and self._running:
                self._running = False
                if self._thread and self._thread.is_alive():
                    self._thread.join(timeout=1.0)  # 添加超时以避免无限等待
                self._thread = None
    def _cleanup(self, _):
        with self._lock:
            self._busses = [wb for wb in self._busses if wb() is not None]

    def _poll(self):
        while True:
            with self._lock:
                if not self._running:
                    break
            evt = CEvent()
            evt.id = 0
            evt.payload = None
            evt.payload_size = 0
            if lib.eb_pop(ctypes.byref(evt)):
                if evt.payload and evt.payload_size > 0:
                    try:
                        # 将void*转换为字符指针并读取数据
                        payload_bytes = ctypes.string_at(ctypes.c_void_p(evt.payload), evt.payload_size)
                        payload_str = payload_bytes.decode('utf-8', errors='replace')
                        with self._lock:
                            snapshot = [ wb() for wb in self._busses if wb() is not None ]
                            for bus in snapshot:
                                if bus is not None:
                                    bus._dispatch(evt.id, payload_str)
                    except Exception as e:
                        print(f"Error processing event payload: {e}")
                    finally:
                        lib.eb_free_payload(ctypes.c_void_p(evt.payload))
                
            else:
                time.sleep(0.01)

class EventBus:
    _poller = _GlobalPoller()
    def __init__(self):
        self._handlers: Dict[int, List[Callable[[str], None]]] = {}
        self._poller.add_bus(self)

    def _dispatch(self, eid: int, payload: str):
        print(f"Event {eid}: {payload}")
        handlers = self._handlers.get(eid, []).copy()
        for h in handlers:
            try:
                h(payload)
            except Exception as e:
                print(f"Error in event handler for event {eid}: {e}")

    def on(self, eid: int, func: Callable[[str], None]):
        self._handlers.setdefault(eid, []).append(func)

    def emit(self, eid: int, payload: str):
        # 将字符串编码为字节
        payload_bytes = payload.encode('utf-8')
        payload_size = len(payload_bytes)
        
        # 创建CEvent对象
        event_ptr = lib.eb_create_event(eid, payload_bytes, payload_size)
        if event_ptr:
            event_ptr = ctypes.cast(event_ptr, ctypes.POINTER(CEvent))
            lib.eb_push(event_ptr)
            # 销毁CEvent对象
            lib.eb_destroy_event(event_ptr)

    def shutdown(self):
        self._poller.remove_bus(self)
        self._handlers.clear()

if __name__ == "__main__":
    bus = EventBus()
    lib.start()

